#pragma once

#include <optix.h>
#include <optixu/optixu_math_namespace.h>
#include <optixu/optixu_vector_types.h>

#include "bsdf_sampling.h"
#include "commonStructs.h"

 using namespace optix;

__device__ __inline__ optix::float4 rect_envmap(rtTextureSampler<float4, 2>& envMap,float3& dir)
{
  float3 direction = dir;
  float theta = atan2f( direction.x, direction.y );
  float phi   = M_PIf * 0.5f -  acosf( direction.z );
  float u     = (theta + M_PIf) * (0.5f * M_1_PIf);
  float v     = 0.5f * ( 1.0f + sin(phi) );

  return tex2D(envMap, u, v);
} 

__device__ __inline__ optix::float4 spheric_envmap_le(rtTextureSampler<float4, 2>& envMap, float3& dir)
{
  float3 direction = -dir;
  float theta = atan2f( direction.x, direction.z );
  float phi   = M_PIf * 0.5f -  acosf( direction.y );
  float u     = (theta + M_PIf) * (0.5f * M_1_PIf);
  float v     = 0.5f * ( 1.0f + sin(phi) );
  return tex2D(envMap, u, v);
} 


__device__ __inline__ void sample_sunsky(const float &solid_angle, const float2 &sample, const float3 ffnormal, float3 &L, float &pdf)
{
	const float z1=sample.x;
	const float z2=sample.y;
	const float cosmax = 1.0f - solid_angle / (2.0f * M_PIf);
    const float z3 = 1.0f - fold(z2) * (1.0f - cosmax);
	
    const float sintheta = sqrtf(1.0f - z3 * z3);
    const float costheta = z3 * z3;
    const float phi = (2.0f * M_PIf) * z1;
    const float cosphi = cosf(phi) * sintheta;
    const float sinphi = sinf(phi) * sintheta;
    float3 v1, v2;
    create_onb(L, v1, v2);
    L = L * costheta + v1 * cosphi + v2 * sinphi;
    pdf = dot( ffnormal, L );
}

__device__ __inline__ void sample_environment(const float3& ffnormal, const float z4, const float z5, float3 &L, float &pdf ) 
{
	sample_direction(ffnormal, z4, z5, 1.0f, L);
    pdf = dot( ffnormal, L );
}

__device__ __inline__ float sample_light(const TriangleLight& light, const float3& ffnormal, const float3& hitpoint, const float z1, const float z2, float3 &L, float &pdf ) 
{
    float alpha = 1.0f - sqrt(fold(z1));
    float beta = (1.0f - fold(z2)) * sqrt(fold(z1));
    float gamma = fold(z2) * sqrt(fold(z1));
    float3 light_pos = light.v3 * gamma + light.v1 * alpha + light.v2 * beta;

    float Ldist = length(light_pos - hitpoint);
    float nDl = dot( ffnormal, L );
    float LnDl = dot( light.normal, L );
    float A = length(cross(light.v2 - light.v3, light.v1 - light.v3));
    L = normalize(light_pos - hitpoint);
    pdf = nDl * LnDl / (M_PIf*Ldist*Ldist) * A;
	return Ldist;
}